package com.example.android.activities

import `in`.srain.cube.views.ptr.PtrDefaultHandler
import `in`.srain.cube.views.ptr.PtrFrameLayout
import `in`.srain.cube.views.ptr.PtrHandler
import `in`.srain.cube.views.ptr.header.StoreHouseHeader
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.*
import androidx.activity.viewModels
import androidx.appcompat.app.ActionBar
import androidx.appcompat.widget.Toolbar
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
import com.example.android.R
import com.example.android.extensions.Alert
import com.example.android.extensions.AlertBar
import com.example.android.extensions.Services
import com.example.android.extensions.SetOnServicesConnected
import com.example.android.fragments.*
import com.example.android.utils.websocket.IMyWebSocketPipeline
import com.example.android.utils.websocket.MyWebSocket
import com.example.android.viewmodels.OnlineChatViewModel
import com.example.android.viewmodels.SharedViewModel
import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

/**
 * @ClassName MainActivity
 * @Author Ryan Kamanri
 * @Date 2022/6/1
 * @Description
 **/
class MainActivity : AppCompatActivity(), IMyWebSocketPipeline {

    private lateinit var _Toolbar: Toolbar
    val Toolbar get() = _Toolbar

    // viewmodels
    private val _SharedViewModel: SharedViewModel by viewModels()

    // fragments in main activity
    val SideBarFragment = SidebarFragment()
    val AnnounceFragment = AnnounceFragment()
    val SelectBedFragment = SelectBedFragment()
    val SelectBedFinishFragment = SelectBedFinishFragment()
    val OnlinePaymentFragment = OnlinePaymentFragment()
    val SelfInfoFragment = SelfInfoFragment()
    val OnlineChatFragment = OnlineChatFragment()



    // callbacks set by every fragment
    private var _CheckCanDoRefresh: () -> Boolean = { false }
    private lateinit var _OnRefreshSuspend: suspend () -> Unit

    fun SetCheckCanDoRefresh(checkCanDoRefresh: () -> Boolean) {
        _CheckCanDoRefresh = checkCanDoRefresh
    }
    fun SetOnRefreshSuspend(onRefreshSuspend: suspend () -> Unit) {
        _OnRefreshSuspend = onRefreshSuspend
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        _Toolbar = findViewById(R.id.bar_main_toolbar)

        SetOnServicesConnected {

            if(!LogInCheckOut()) return@SetOnServicesConnected

            SetFragmentTransaction()

            SetPtrFrame()

            Services.WebSocket
                .AddPipeline(this)
                .AddPipeline(OnlineChatFragment)
                .Open()

            if (intent.getStringExtra(LoginActivity.LOGIN_KEY) != null) {
                AlertBar {
                    it.setTitle("欢迎你")
                    it.setText("登录成功")
                }
            }
        }


    }


    private fun LogInCheckOut(): Boolean {
        val token = Services.HashMapStorage["token"]
        if(token == null) {
            val intent = Intent(applicationContext, LoginActivity::class.java)
            startActivity(intent)
            finish() // Destroy this activity
            return false
        }
        return true
    }

    private fun SetFragmentTransaction() {
        supportFragmentManager.beginTransaction()
            .replace(R.id.content_main_fragment, AnnounceFragment)
            .replace(R.id.menu_main_side_bar_fragment, SideBarFragment)
            .commit()

    }


    private fun SetPtrFrame() {
        val ptrFrame = findViewById<PtrFrameLayout>(R.id.main_ptr_frame)

        val header = StoreHouseHeader(this)
        header.setPadding(0, 15,0,0)
        header.initWithStringArray(R.array.storehouse)
        header.setTextColor(R.color.crane_purple_900)


        ptrFrame.headerView = header
        ptrFrame.addPtrUIHandler(header)
        ptrFrame.disableWhenHorizontalMove(true)


        ptrFrame.setPtrHandler(object : PtrHandler
        {
            override fun checkCanDoRefresh(
                frame: PtrFrameLayout?,
                content: View?,
                header: View?
            ): Boolean {
                if(!_CheckCanDoRefresh()) return false
                return PtrDefaultHandler.checkContentCanBePulledDown(frame, content, header)
            }

            override fun onRefreshBegin(frame: PtrFrameLayout?) {
                lifecycleScope.launch(Dispatchers.Main) {
                    kotlin.runCatching {
                        if(!Services.WebSocket.IsOpen) {
                            Services.WebSocket.TryReconnect()
                        }
                        _OnRefreshSuspend()
                    }.onFailure {
                        ptrFrame.refreshComplete()

                        //Alert("系统或网络错误, 请稍后重试 (${it.message})", Snackbar.LENGTH_INDEFINITE)
                        //Log.e(toString(), "Failed To Refresh Caused By: ${it.message}")

//                        Alert("系统或网络错误, 请稍后重试 (${it.message})", Snackbar.LENGTH_LONG)
                        Log.e(toString(), "Failed To Refresh Caused By: ${it.message}")

                        it.printStackTrace()
                    }.onSuccess {
                        ptrFrame.refreshComplete()
                        Alert("刷新成功!")
                    }
                }
            }
        })
    }

    /**
     * myWebSocket预处理管线
     * 让所在的Activity/Fragment实现IMyWebSocketPipeline接口
     * 并在此方法中添加需要的路由和处理方法
     * 然后调用MyWebSocket.AddPipeline(IMyWebSocketPipeline)将管线接入
     */
    override fun MyWebSocketExecutor(myWebSocket: MyWebSocket) {
        myWebSocket.SetOnOpenHandler {
            Alert("连接到服务器")
        }.SetOnClosedHandler {
            Alert("断开与服务器的连接", Snackbar.LENGTH_INDEFINITE)
        }.SetOnFailureHandler {
            Alert("连接服务器失败", Snackbar.LENGTH_INDEFINITE)
        }.AddEventHandler(MyWebSocket.WebSocketMessageEvent.OnServerConnect) {
            val assignedId = it[0].Message.toString()
            runOnUiThread {
                Alert("WebSocket Assigned Id: $assignedId", Snackbar.LENGTH_INDEFINITE)
                Log.d(toString(),"Receive Assigned Id $assignedId")
            }
            Services.HashMapStorage["WebSocketAssignedId"] = assignedId

            // get self info and return Id
            lifecycleScope.launch{
                Services.SharedService.GetSelfInfo(_SharedViewModel)
                val selfId = _SharedViewModel.getSelf().value!!.id!!
                myWebSocket.SendMessages(arrayListOf(
                    MyWebSocket.WebSocketMessage(
                        MyWebSocket.WebSocketMessageEvent.OnClientConnect,
                        MyWebSocket.WebSocketMessageType.Text,
                        assignedId
                    ),
                    MyWebSocket.WebSocketMessage(
                        MyWebSocket.WebSocketMessageEvent.OnClientConnect,
                        MyWebSocket.WebSocketMessageType.Text,
                        selfId.toString()
                    )
                ))
            }

            return@AddEventHandler arrayListOf()
        }
    }
}